using System;
using System.Collections;
using System.Collections.Specialized;
using System.Data;
using System.DirectoryServices;
using System.IO;
using System.Text.RegularExpressions;
using System.Web.Services;
using Microsoft.ApplicationBlocks.ExceptionManagement;
using Dimok;
using Dimok.Concurrency;
using Config = Dimok.Config;
using Dimok.Data;
using Dimok.Exceptions;
using Dimok.Data.Database;

namespace Dimok.User {

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>	User object. </summary>
	///
	/// <remarks>	Dimon, 12/21/2010. </remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////

	public class UserObject:UserObjectBase{
		
		private static Hashtable groupInfosCache = Hashtable.Synchronized(new Hashtable());
		private static Hashtable groupsCache = Hashtable.Synchronized(new Hashtable());

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Resets the group infos cache. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static void ResetGroupInfosCache(){groupInfosCache.Clear();}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Resets the group infos cache. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="myselfOnly">	true to myself only. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static void ResetGroupInfosCache(bool myselfOnly){ResetGroupInfosCache(CurrentUserPath);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Resets the group infos cache. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="userPath">	Full pathname of the user file. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static void ResetGroupInfosCache(string userPath){groupInfosCache.Remove(userPath);}

		public const string NAMESPACE_DIVIDER = "/";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Default constructor. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public UserObject():base(){}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Constructor. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="userPath">	Full pathname of the user file. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public UserObject(string userPath):base(userPath){}

		#region GroupInfo class

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Information about the group. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public class GroupInfo:IComparable{
			public string Name = "";
			public StringList NameSpacePath = new StringList();
			public string DN;
			DirectoryEntry groupObject;
			/// <summary>
			/// WinnNT style
			/// </summary>
			/// <param name="dn">Web_AFC_Aloaners_Admin</param>
			/// <param name="nameSpace"></param>
			public GroupInfo(string sAM){//DDD
				DN = sAM;
				//DDDstring subSpace = GetSubSpace(DN);
				//DDDstring[] parts = subSpace.Split('_');
				Name = "Admin";//DDD parts[parts.Length - 1];
				//DDDNameSpacePath = GetNameSpacePath(subSpace);
			}
			public GroupInfo(DirectoryEntry group){
				GroupObject = group;
				DN = ADs.Props.DN(group);
				DirectoryEntry deNS = GroupsOU;
				if( deNS == null )return;
				deNS = deNS.Parent;
				string link;
				try{
					do{
						link = ADs.Props.CN(deNS);
						if( link.ToLower() == AppSpace.ToLower() )break;
						NameSpacePath.Insert(0,link);
						deNS = deNS.Parent;
					//}while( deNS.Path.Split('=').Length > 2 );// ADs.Props.CN(deNS).ToLower() != "web" );
					}while( ADs.LDAP.domainContext != ADs.Props.DN(deNS) );
				}catch(Exception exc){
					exc.Data["DN"] = DN;
					try {
						exc.Data["deNS.Path"] = deNS.Path;
					} catch { }
					throw;
				}
				if( link.ToLower() == AppSpace.ToLower() )Name = ADs.Props.CN(GroupObject);
			}
			public DirectoryEntry GroupObject{
				get{return groupObject;}
				set{groupObject = value;}
			}
			public DirectoryEntry GroupsOU{get{return GetGroupsOU(GroupObject);}}
			public DirectoryEntry NameSpaceOU{get{return GroupsOU.Parent;}}
			public string NameSpace{get{return NameSpacePath.Join(NAMESPACE_DIVIDER);}}
			public bool IsInAppSpace{get{return Name != "";}}
			public override string ToString(){return (string)this;}
			static public implicit operator string(GroupInfo group){
				return group.NameSpace+"/"+group.Name;
			}
			public static StringList GetNameSpacePath(string subSpace){
				StringList al = new StringList(subSpace,'_');
				al.RemoveAt(al.Count-1);
				return al;
			}
			public static string GetSubSpace(string groupDN){
				return Regex.Replace(groupDN,WebSpace+"_?","",RegexOptions.IgnoreCase|RegexOptions.Compiled);
			}//Aloaners_Admin
			public int CompareTo(object o){return Name.CompareTo(((GroupInfo)o).Name);}
		}
		#endregion

		#region GroupInfoList class

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	List of group informations. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public class GroupInfoList : ArrayList{
			public GroupInfoList(){}
			public new GroupInfo this[int index]{
				get{ return (GroupInfo)base[index]; }
			}
			public int Add(GroupInfo giValue ){ 
				foreach( GroupInfo gi in this )
					if( giValue.NameSpace.Length > gi.NameSpace.Length )
						return -1;
					else if( giValue.NameSpace.Length < gi.NameSpace.Length ){
						this.Clear();
						break;
					}
				return base.Add(giValue); 
			}

			public StringList GroupNamesToShow{get{return GetGroupNames(new Regex("^_"));}}
			public StringList GroupNames{ get{return GetGroupNames(null);}}
			public StringList GetGroupNames(Regex exceptFilter){
				StringList slGNs = new StringList();
				foreach( GroupInfo gi in this )
					if( exceptFilter == null || !exceptFilter.IsMatch(gi.Name) )
						slGNs.Add(gi.Name);
				return slGNs;
			}
			public bool ContainsOne(params string[] groupNames){
				foreach(string groupName in groupNames)
					if( Contains(groupName) )return true;
				return false;
			}
			public bool ContainsAll(params string[] groupNames){
				foreach(string groupName in groupNames)
					if( !Contains(groupName) )return false;
				return true;
			}
			public bool Contains(string groupName){
				groupName = groupName.ToLower();
				foreach( GroupInfo gi in this )
					if( gi.Name.ToLower() == groupName )return true;
				return false;
			}
			public bool Contains(Regex groupTemplate){
				foreach( GroupInfo gi in this )
					if( groupTemplate.IsMatch(gi.Name) )return true;
				return false;
			}
			public GroupInfo Find(Regex groupTemplate){
				foreach( GroupInfo gi in this )
					if( groupTemplate.IsMatch(gi.Name) )return gi;
				return null;
			}
		}
		#endregion GroupInfoList class

		#region GroupInfos property

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets or sets the al group infos. </summary>
		///
		/// <value>	The al group infos. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public GroupInfoList alGroupInfos{
			get{ return groupInfosCache.Contains(UserPath) ?
						 (GroupInfoList)groupInfosCache[UserPath] :
						 alGroupInfos = new GroupInfoList();}
			set{
				if( groupInfosCache.Contains(UserPath) ) groupInfosCache[UserPath] = value;
				else groupInfosCache.Add(UserPath,value);
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the group infos. </summary>
		///
		/// <value>	The group infos. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public GroupInfoList GroupInfos{
			get{
				lock(groupInfosCache.SyncRoot){
					if( alGroupInfos.Count > 0 )return alGroupInfos;
					StringList slGroups = new StringList();
					if( !ADs.isInDomain(UserPath) )
						foreach(string group in base.Groups )
							alGroupInfos.Add(new GroupInfo(group));
					else
						foreach( string sAM in ADs.GetUserGroups(LdapUser,"") )
							try {
								GroupInfo gi = new GroupInfo(ADs.LDAP.GetUser(sAM,"group"));
								if( gi.IsInAppSpace )alGroupInfos.Add(gi);
								slGroups.Add(gi+"");
							} catch (Exception exc) {
								exc.Data["sAM"] = sAM;
								throw;
							}
					if (alGroupInfos.Count == 0) {
						Exception exc = new Exception(DisplayName + " is not a member of any WEB group.\n" + slGroups.Join("\n") + "\nGo see Administrator.");
						exc.Data.Add("UserPath", UserPath);
						throw exc;
					}
					alGroupInfos.Sort();
					return alGroupInfos;
				}
			}
		}
		#endregion

		#region Groups/User Info

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the groups ou. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="deGroup">	Group the de belongs to. </param>
		///
		/// <returns>	The groups ou. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DirectoryEntry GetGroupsOU(DirectoryEntry deGroup){
			return ADs.FindParentByName(deGroup,Config.ADS.GroupsOUName);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the groups in name space. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	The groups in name space. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private ADsGroupDS GetGroupsInNameSpace(){return GetGroups(GroupsDN);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the groups. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="Exception">	Thrown when exception. </exception>
		///
		/// <param name="GroupsDN">	The groups dn. </param>
		///
		/// <returns>	The groups. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private ADsGroupDS GetGroups(string GroupsDN){
			try{
				return GetGroups(new ADs.DirectoryEntryEx(GroupsDN));
			}catch(Exception exc){throw new Exception(GroupsDN,exc);}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the groups. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="groupsOU">	The groups ou. </param>
		///
		/// <returns>	The groups. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private ADsGroupDS GetGroups(DirectoryEntry groupsOU){
			ADsGroupDS.t_GroupDataTable dtGroups = ADs.LDAP.FindGroupsDS(groupsOU,false).t_Group;
			SQLHelperEx.SortTable(dtGroups,"CN");
			return (ADsGroupDS)dtGroups.DataSet;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets all groups in namespace. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	all groups in namespace. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public ADsGroupDS GetAllGroupsInNamespace() { return GetAllGroupsInNamespace(""); }

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets all groups in namespace. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="cnRegExFilter">	The cn register ex filter. </param>
		///
		/// <returns>	all groups in namespace. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public ADsGroupDS GetAllGroupsInNamespace(string cnRegExFilter){
			ADsGroupDS.t_GroupDataTable dtGroup = ADs.LDAP.FindGroupsDS(GroupsDN,cnRegExFilter,true).t_Group;
			SQLHelperEx.SortTable(dtGroup,"dn");
			return (ADsGroupDS)dtGroup.DataSet;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets all users in namespace. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	all users in namespace. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public ADsUser GetAllUsersInNamespace(){
			ADsUser dsUsersAll = null;
			if( IsInDomain){
				foreach( DirectoryEntry deGroup in ADs.LDAP.FindGroups(GroupsDN) )
					dsUsersAll = ADs.LDAP.ListGroupUsers(deGroup,dsUsersAll);
				SQLHelperEx.SortTable(dsUsersAll.th_AdsUser,"Name");
			}else dsUsersAll = new ADsUser();
			return dsUsersAll;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a group users. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="Exception">	Thrown when exception. </exception>
		///
		/// <param name="groupName">	Name of the group. </param>
		///
		/// <returns>	The group users. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public ADsUser GetGroupUsers(string groupName){
			ADsUser ds = new ADsUser();
			if(	IsInDomain ){
				string groupDN = GroupDN(groupName);
				if (groupDN != "") {
					ds = ADs.LDAP.ListGroupUsers(groupDN);
					if (ds.th_AdsUser.Count == 0) throw new Exception("No people in " + groupDN);
				}
			}
			ds.Namespace = "";
			return ds;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Is member of the given group name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="groupName">	Name of the group. </param>
		///
		/// <returns>	true if member of, false if not. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public bool IsMemberOf(string groupName){return GroupInfos.Contains(groupName);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Is member of the given group name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="groupTemplate">	The group template. </param>
		///
		/// <returns>	true if member of, false if not. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public bool IsMemberOf(Regex groupTemplate){return GroupInfos.Contains(groupTemplate);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Query if 'groupNames' is member of one. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="groupNames">	List of names of the groups. </param>
		///
		/// <returns>	true if member of one, false if not. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public bool IsMemberOfOne(params string[] groupNames){return GroupInfos.ContainsOne(groupNames);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Query if 'groupNames' is member of all. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="groupNames">	List of names of the groups. </param>
		///
		/// <returns>	true if member of all, false if not. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public bool IsMemberOfAll(params string[] groupNames){return GroupInfos.ContainsAll(groupNames);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a value indicating whether this object is admin. </summary>
		///
		/// <value>	true if this object is admin, false if not. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public bool IsAdmin{get{return IsMemberOfOne("Admin","Admins");}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the mail. </summary>
		///
		/// <value>	The mail. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string Mail{get{return ADs.Props.Mail(LdapUser);}}
		#endregion
		
		#region Overrides
		private DirectoryEntry nameSpaceOU = null;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the name space ou. </summary>
		///
		/// <value>	The name space ou. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public DirectoryEntry NameSpaceOU{
			get{return ADs.isInDomain(UserPath) ? (nameSpaceOU != null ? nameSpaceOU : nameSpaceOU = GroupInfos[0].NameSpaceOU) : null;}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the name space dn. </summary>
		///
		/// <value>	The name space dn. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string NameSpaceDN{
			get{return NameSpaceOU != null ? ADs.Props.DN(NameSpaceOU) : "";}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the groups ou. </summary>
		///
		/// <value>	The groups ou. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public DirectoryEntry GroupsOU{
			get{return ADs.isInDomain(UserPath) ? GroupInfos[0].GroupsOU : null;}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the groups dn. </summary>
		///
		/// <value>	The groups dn. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string GroupsDN{
			get{return GroupsOU != null ? ADs.Props.DN(GroupsOU) : "";}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Group dn. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="groupName">	Name of the group. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string GroupDN(string groupName){
			if( groupsCache.Contains(groupName) )return groupsCache[groupName]+"";
			DirectoryEntry deGroup = ADs.LDAP.FindGroup(GroupsOU,groupName, SearchScope.Subtree);
			if (deGroup == null) return "";
			groupsCache.Add(groupName,deGroup.Path);
			return GroupDN(groupName);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Returns NameSpace string: AAAA/BBBB/CCCC. </summary>
		///
		/// <value>	The name space. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string NameSpace{get{return GroupInfos[0].NameSpace;}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the groups. </summary>
		///
		/// <value>	The groups. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public new string[] Groups{get{return GroupInfos.GroupNames;}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Groups to show on main page. </summary>
		///
		/// <value>	The groups to show. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public StringList GroupsToShow{get{return GroupInfos.GroupNamesToShow;}}

		#endregion
	
		#region DB Connection ==============

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a value indicating whether this object is a fc. </summary>
		///
		/// <value>	true if this object is a fc, false if not. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		static bool isAFC { get { return applIDParam < 1000000 && applIDParam != APPL_ID_UNDEFINED; } }

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the name of the database. </summary>
		///
		/// <value>	The name of the database. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string DBName{get{return Config.db.dbName;}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Builds a connection string. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="rawConn">	The raw connection. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static string BuildConnString(string rawConn) {
			return BuildConnString(rawConn, !isAFC ? Config.db.dbName : Config.db.dbName_AFC);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Builds a connection string. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="rawConn">	The raw connection. </param>
		/// <param name="dbName">		Name of the database. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static string BuildConnString(string rawConn,string dbName){
			string serverName = Config.db.dbServer;
			if (dbName.Contains(".")) {
				serverName = dbName.Split('.')[0];
				dbName = dbName.Split('.')[1];
			}
			return rawConn.Replace("~dbServer~",serverName).Replace("~dbName~",dbName);
			//.Replace("~user~",Registry.dbUser).Replace("~pass~",Registry.dbPass);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database raw. </summary>
		///
		/// <value>	The database raw. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string dbRaw{get{return BuildConnString(Config.db.conn);}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database raw ado. </summary>
		///
		/// <value>	The database raw ado. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string dbRawAdo{get{return BuildConnString(Config.db.connADO);}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database raw images. </summary>
		///
		/// <value>	The database raw images. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string dbRaw_Images{
			get{
				return BuildConnString(Config.db.conn, !isAFC ? Config.db.dbName_Images : Config.db.dbName_Images_AFC);
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database raw gl. </summary>
		///
		/// <value>	The database raw gl. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string dbRaw_GL{get{return BuildConnString(Config.db.conn,Config.db.dbName_GL);}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the host name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		protected string HostName(){return HostName(string.Join(",",Groups)+"."+UserName);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the host name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="workstationID">	Identifier for the workstation. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		protected static string HostName(string workstationID){return ";Workstation ID="+workstationID;}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the application name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		protected string AppName(){return AppName(NameSpace);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the application name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="nameSpace">	The name space. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		protected static string AppName(string nameSpace){return ";Application Name="+(nameSpace==""?"~":nameSpace);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a user connection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="rawConn">	The raw connection. </param>
		///
		/// <returns>	The user connection. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string GetUserConn(string rawConn){return rawConn+AppName()+HostName();}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a user connection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="groupAndName">	Name of the group and. </param>
		/// <param name="nameSpace">		The name space. </param>
		///
		/// <returns>	The user connection. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string GetUserConn(string groupAndName,string nameSpace){return GetUserConn(dbRaw,groupAndName,nameSpace);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a user connection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="rawConn">			The raw connection. </param>
		/// <param name="groupAndName">	Name of the group and. </param>
		/// <param name="nameSpace">		The name space. </param>
		///
		/// <returns>	The user connection. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string GetUserConn(string rawConn,string groupAndName,string nameSpace){
			return rawConn+HostName(groupAndName)+AppName(nameSpace);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the admin image connection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	The admin image connection. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string GetAdminImageConn(){return GetAdminDBConn(dbRaw_Images);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the admin gl connection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	The admin gl connection. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string GetAdminGLConn(){return GetAdminDBConn(dbRaw_GL);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the admin database connection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	The admin database connection. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string GetAdminDBConn(){return GetAdminDBConn(dbRaw);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the admin database connection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="connString">	The connection string. </param>
		///
		/// <returns>	The admin database connection. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string GetAdminDBConn(string connString){
			return connString+";Workstation ID=Admin.System;Application Name=.";
		}
		
		private string _db = "";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets or sets the database. </summary>
		///
		/// <value>	The database. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string db{
			get{return _db != "" ? _db : (_db=GetUserConn(dbRaw));}
			set{_db = value;}
		}
		
		private string _db_Images = "";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database images. </summary>
		///
		/// <value>	The database images. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string db_Images{get{return _db_Images != "" ? _db_Images : (_db_Images=GetUserConn(dbRaw_Images));}}

		private string _db_GL = "";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database gl. </summary>
		///
		/// <value>	The database gl. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string db_GL{get{return _db_GL != "" ? _db_GL : (_db_GL=GetUserConn(dbRaw_GL));}}

		private string _dbADO = "";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database a do. </summary>
		///
		/// <value>	The database a do. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string dbADO{get{return _dbADO != "" ? _dbADO : (_dbADO=GetUserConn(BuildConnString(Config.db.connADO)));}}

		private string _dbADO_Image = "";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database a do image. </summary>
		///
		/// <value>	The database a do image. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string dbADO_Image{
			get{
				return _dbADO_Image != "" ? _dbADO_Image :
					(_dbADO_Image = GetUserConn(BuildConnString(Config.db.connADO, !isAFC ? Config.db.dbName_Images : Config.db.dbName_Images_AFC)));
			}
		}

		private string _dbADO_GL = "";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the database a do gl. </summary>
		///
		/// <value>	The database a do gl. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string dbADO_GL{get{return _dbADO_GL != "" ? _dbADO_GL : (_dbADO_GL=GetUserConn(BuildConnString(Config.db.connADO,Config.db.dbName_GL)));}}

		#endregion DB Connection ==============

		#region ApplID
		#region ========= Filters =========

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the borrower filter. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string BorrowerFilter(){return BorrowerFilter(applID);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the borrower filter. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="position">	The position. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string BorrowerFilter(byte position){return BorrowerFilter(applID,position);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the borrower filter. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="applID">	. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string BorrowerFilter(int applID){return BorrowerFilter(applID,-1);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the borrower filter. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="applID">		. </param>
		/// <param name="position">	The position. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string BorrowerFilter(int applID,int position){
			return "ID IN (SELECT BorrowerID FROM "+Config.db.ApplicantBorrowerTable+" WHERE "+Config.db.ApplID+"="+applID+(position<0?"":" AND Pos="+position)+")";
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the applicant filter. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string ApplicantFilter(){return ApplicantFilter(applIDSec);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the applicant filter. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="applID">	. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string ApplicantFilter(int applID){
			return Config.db.ApplID+" = "+applID;
			//Config.db.ApplicationFilter.Replace("~~ID~~",applID+"");
		}
		#endregion ========================
		private bool _applIDChecked = false;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the appl identifier security. </summary>
		///
		/// <value>	The appl identifier security. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public virtual int applIDSec{
			get{
				if( !_applIDChecked )_applIDChecked = applID == GetSecuredApplID(db,applID);
				return applID;
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a secured appl identifier. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="ApplicationException">	Thrown when application. </exception>
		///
		/// <param name="db">			The database. </param>
		/// <param name="applID">	. </param>
		///
		/// <returns>	The secured appl identifier. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static int GetSecuredApplID(string db,int applID){
			object oAID = SQLHelperEx.ExecuteScalarEx(db,Dimok.Config.db.ApplIDSec,applID);
			if( oAID == null || oAID == System.DBNull.Value )throw new ApplicationException("Access denied or "+Config.db.ApplID+" "+applID+" does not exist.");
			return (int)oAID;
		}

		#endregion
		#region MenuID

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets or sets the identifier of the menu. </summary>
		///
		/// <value>	The identifier of the menu. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public virtual int menuID{
			get{
				if( m_menuID != MENU_ID_UNDEFINED )return m_menuID;
				if( hasApplID ){
					object mid = null;
					mid = SQLHelperEx.ExecSP(db, "s_MenuIDEx",applID);
					if( mid == null || (int)mid == 0 )throw new NoMenuIDException(m_applID);
					m_menuID = (int)mid;
				}else{
					m_menuID = menuIDParam;
					if( m_menuID == MENU_ID_UNDEFINED )throw new NoMenuIDException(0);
				}
				return m_menuID;
			}
			set{
				if( hasApplID )SetMenuID(applID,db,value);
				m_menuID = value;
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets a menu identifier. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="applID">	. </param>
		/// <param name="db">			The database. </param>
		/// <param name="menuID">	Identifier for the menu. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static void SetMenuID(int applID,string db,int menuID){
			SQLHelperEx.ExecSP(db,"s_MenuIDEx",applID,menuID);
		}
		#endregion

		#region ADs User/Groups

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Creates a user. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="userName">		Name of the user. </param>
		/// <param name="password">		The password. </param>
		/// <param name="groupName">	Name of the group. </param>
		/// <param name="firstName">	Name of the first. </param>
		/// <param name="lastName">		Name of the last. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public void CreateUser(string userName, string password,string groupName,string firstName,string lastName){
			StringDictionary sc = new StringDictionary();
			sc.Add("givenName",firstName);
			sc.Add("sn",lastName);
			ADs.LDAP.CreateUser(NameSpaceOU,userName,password,sc,new string[]{GroupsOU.Children.Find("CN="+groupName,"Group").Path,ADs.LDAP.FindGroup(new DirectoryEntry(),"WebGroups", SearchScope.Subtree).Path},true,false);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Creates a company. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="ClientException">	Thrown when client. </exception>
		/// <exception cref="Exception">				Thrown when exception. </exception>
		///
		/// <param name="parentNameSpaceDN">	The parent name space dn. </param>
		/// <param name="companyName">				Name of the company. </param>
		/// <param name="userName">						Name of the user. </param>
		/// <param name="password">						The password. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public DirectoryEntry CreateCompany(string parentNameSpaceDN,string companyName,string userName,string password){
			if( companyName == "" )throw new ClientException("Company name must not be empty!");
			if( userName == "" )throw new ClientException("User name must not be empty!");
			if( password == "" )throw new ClientException("Password name must not be empty!");
			bool recreate = companyName.Split(':')[0] == "DEL"; 
			if( recreate )
				companyName = companyName.Split(':')[1];
			DirectoryEntry deOU = null;
			deOU = parentNameSpaceDN == "" ? new ADs.DirectoryEntryEx(Config.ADS.ApplicationDN) : ADs.LDAP.GetOU(parentNameSpaceDN,Config.ADS.ApplicationDN,true);
			try{deOU = ADs.LDAP.CreateOU(companyName,deOU);
			}catch(ObjectExistsException exc){
				if( recreate ){
					exc.deObject.DeleteTree();
					SQLHelperEx.ExecuteNonQueryEx(GetAdminDBConn(),"DELETE FROM t_NameSpace WHERE NameSpace=@NS",companyName);
					deOU = ADs.LDAP.CreateOU(companyName,deOU);
				}else
					throw new Exception("Company "+companyName+" already exists.\n\nPick another one.");
			}
			DirectoryEntry deGroups = ADs.LDAP.CreateOU("_Groups",deOU);
			string adminGroupPath = "";
			try{
				string parentGroupsDN = "OU="+Config.ADS.GroupsOUName+","+ADs.Props.DN(deOU.Parent);
				foreach( ADsGroupDS.t_GroupRow row in GetGroups(parentGroupsDN).t_Group )
					try{
						//if( Regex.Match(row.cn,"^admin$",RegexOptions.IgnoreCase).Success )continue;
						DirectoryEntry deGroup = ADs.LDAP.CreateGroup(row.cn+"{"+Guid.NewGuid().ToString().ToUpper()+"}",deGroups);
						if( adminGroupPath == "" && Regex.IsMatch(row.cn,"admin",RegexOptions.IgnoreCase) )
							adminGroupPath = deGroup.Path;
					}catch(ObjectExistsException exc){
						throw new ClientException("Group "+exc.deObject+" already exists!");
					}
				if( adminGroupPath == "" )throw new Exception("No Admin group found in "+parentGroupsDN+".");
				DirectoryEntry deUser = ADs.LDAP.CreateUser(deOU,userName,password,null,new string[]{ADs.LDAP.FindGroup(new DirectoryEntry(),"WebGroups", SearchScope.Subtree).Path,adminGroupPath},true,false);
				string dbNS = GetNameSpaceFromDN(ADs.Props.DN(deUser.Parent));
				try{
					SQLHelperEx.ExecuteNonQueryEx(GetAdminDBConn(),"INSERT INTO t_NameSpace(NameSpace)VALUES(@NS)",dbNS);
				}catch(Exception exc){ throw new Exception(dbNS,exc); }
				//SQLHelperEx.ExecuteNonQuery(dbRaw,"s_NameSpace_Add",companyName,parentNameSpace);
				return deUser;
			}catch(UserExistsException exc){
				deOU.DeleteTree();
				throw new Exception("adminGroupPath:"+adminGroupPath,exc);
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a name space from dn. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="Exception">	Thrown when exception. </exception>
		///
		/// <param name="dn">	The dn. </param>
		///
		/// <returns>	The name space from dn. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		protected static string GetNameSpaceFromDN(string dn){
			string pattern = "^OU=(.+),"+Config.ADS.ApplicationDN;
			string nameSpaceDN = Regex.Match(dn,pattern,RegexOptions.IgnoreCase).Groups[1].Value;
			if( nameSpaceDN == "" )throw new Exception("DN:"+pattern);
			string[] nsArray = Regex.Split(nameSpaceDN,",OU=",RegexOptions.IgnoreCase);
			Array.Reverse(nsArray);
			return string.Join("/",nsArray);
		}
		private const string SQL_USERS_GROUPS = @"
BEGIN TRAN
DELETE   FROM t_GroupsUsers WHERE NameSpaceID = dbo.UserNameSpaceID()
SELECT * FROM t_GroupsUsers WHERE NameSpaceID = dbo.UserNameSpaceID()
COMMIT TRAN
";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the groups users. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	The groups users. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public Dimok.Data.DS.UsersGroupsDS GetGroupsUsers(){
			Dimok.Data.DS.UsersGroupsDS dsUG = new Dimok.Data.DS.UsersGroupsDS();
			foreach(ADsGroupDS.t_GroupRow rowGroup in GetAllGroupsInNamespace().t_Group )
				foreach( ADsUser.th_AdsUserRow rowUser in ADs.LDAP.ListGroupUsers(rowGroup.dn).th_AdsUser )
					dsUG.UsersGroups.AddUsersGroupsRow(rowGroup.cn,rowUser.UserName,rowUser.Name);
			SQLHelperEx.SortTable(dsUG.UsersGroups,"GroupName,UserName");
			SQLHelperEx.UpdateDataTable(dsUG.UsersGroups,db,SQL_USERS_GROUPS);
			return dsUG;
		}

		#endregion

		#region Concurrancy

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Query if this object is managed menu. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	true if managed menu, false if not. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public bool IsManagedMenu(){
			return (bool)SQLHelperEx.ExecuteScalarEx(db,"SELECT IsManaged FROM v_Menu WHERE MenuID=@MenuID",menuID);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the appl lock time out. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	The appl lock time out. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public TimeSpan GetApplLockTimeOut(){
			object timeOut = SQLHelperEx.ExecuteScalarEx(db,"SELECT ApplLockTimeOut FROM v_Menu WHERE MenuID=@MenuID",menuID);
			return timeOut==System.DBNull.Value ? Config.application.ApplLockTimeOut : new TimeSpan(0,0,(int)timeOut);		
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Lock applicant from shared queue. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="applID">	. </param>
		///
		/// <returns>	true if success. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public bool LockNextApplicant(int applID){
			if( Locker.IsLocked(applID) )return false;
			LockApplicant(applID);
			return true;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Locks the applicant. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="applID">	. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string LockApplicant(int applID){
			if( applID <= 0 )return Locker.LockApplicant(applID);
			return Locker.LockApplicant(applID,GetApplLockTimeOut());
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Locks the applicant. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string LockApplicant(){return LockApplicant(applID,menuID);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Locks the applicant. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="applID">	. </param>
		/// <param name="menuID">	Identifier for the menu. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string LockApplicant(int applID,int menuID){
			return Locker.LockApplicant(applID,GetApplLockTimeOut());
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a value indicating whether this object has page session identifier. </summary>
		///
		/// <value>	true if this object has page session identifier, false if not. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static bool HasPageSessionID{get{return Locker.PageSessionIDHeader != "";}}

		/// <summary>
		/// Don't lock applicant (if it's in frame)
		/// </summary>
		#endregion Concurrancy ===================

		#region Pages

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the pages. </summary>
		///
		/// <value>	The pages. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public DataSet Pages{get{return GetPages(db,applID,menuID);}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the pages. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="db">			The database. </param>
		/// <param name="applID">	. </param>
		/// <param name="menuID">	Identifier for the menu. </param>
		///
		/// <returns>	The pages. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataSet GetPages(string db,int applID,int menuID){
			return SQLHelperEx.ExecuteDatasetEx(db,"SELECT PageID, PageURL+'"+applID+"&"+Locker.NoLockParam+"' AS PageURL, PageDesc, TabIndex FROM fs_MenuPages(@MenuID,0)ORDER BY TabIndex",menuID);
		}
		#endregion

		#region Virtuals
		protected object _applInfo = null;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the appl information v. </summary>
		///
		/// <value>	The appl information v. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		protected virtual object _applInfo_v{get{return _applInfo==null ? _applInfo=new ApplInfoClass(this) : _applInfo;}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the information describing the appl. </summary>
		///
		/// <value>	Information describing the appl. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public ApplInfoClass ApplInfo{get{return (ApplInfoClass)_applInfo_v;}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Appl information class. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public class ApplInfoClass{
			protected UserObject uox;
			protected DataRow _row = null;
			public ApplInfoClass(UserObject uox){this.uox = uox;}
			protected virtual string ApplInfo_V{get{return "SELECT a.*,m.MenuPath FROM "+Dimok.Config.db.ApplInfoView+" a INNER JOIN v_Menu m ON a."+Dimok.Config.db.MenuID+" = m.MenuID WHERE "+uox.ApplicantFilter();}}
			public virtual DataRow Row(){
				if( _row != null )return _row;
				DataRowCollection rows = SQLHelperEx.ExecuteDatasetEx(uox.db,ApplInfo_V).Tables[0].Rows;
				return rows.Count > 0 ? rows[0] : null;
			}
			protected object Get(){
				try{
					return Row()==null?null:Row()[Common.GetFuncName(1)];
				}catch(Exception exc){
					throw new ClientException(exc,"SQL",ApplInfo_V);
				}
			}
			public virtual object Get(string name){return Row()[name];}
			public virtual string FirstName(){return Get()+"";}
			public virtual string LastName(){return Get()+"";}
			public virtual string MenuPath(){return Get()+"";}
			public virtual string FullName(){return FirstName()+" "+LastName();}
			public virtual string GetXml(){return Row().Table.DataSet.GetXml();}
			public int BorrowerID(int position){return BorrowerID(uox.db,uox.applIDSec,position);}
			public static int BorrowerID(string db,int applID, int position){
				object o = SQLHelperEx.ExecuteScalarEx(db,"SELECT BorrowerID FROM "+Config.db.ApplicantBorrowerTable+" WHERE "+Config.db.ApplID+"=@ApplID AND Pos=@Pos",applID,position);
				return o == null ? 0 : (int)o;
			}
		}
		#endregion
	}
}
